package com.dawn.module.hospital.util;

/**
 * @description:
 * @author: cnsu-cmh
 * @time: 2024/10/22 16:16
 */

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.*;

/**
 * 基于dom4j的工具包
 */
public class Dom4jUtils {

    /**
     * 创建文档
     * @param lableName 根标签
     * @return
     */
    public static Document createDocument(String lableName){
        Document document = DocumentHelper.createDocument();
        document.addElement(lableName);
        return document;
    }

    /**
     * 通过文件的路径获取xml的document对象
     *
     * @param path  文件的路径
     * @return      返回文档对象
     */
    public static Document getDocumentByFilePath(String path) {
        if (null == path) {
            return null;
        }
        Document document = null;
        try {
            SAXReader reader = new SAXReader();
            document = reader.read(new File(path));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return document;
    }

    /**
     * 通过xml字符获取document文档
     * @param xmlstr    要序列化的xml字符
     * @return          返回文档对象
     * @throws DocumentException
     */
    public static Document getDocumentByXml(String xmlstr) throws DocumentException{
        if(xmlstr==""||xmlstr==null){
            return null;
        }
        Document document = DocumentHelper.parseText(xmlstr);
        return document;
    }

    /**
     * 获取某个元素的所有的子节点
     * @param node  制定节点
     * @return      返回所有的子节点
     */
    public static List<Element> getChildElements(Element node) {
        if (null == node) {
            return null;
        }
        @SuppressWarnings("unchecked")
        List<Element> lists = node.elements();
        return lists;
    }

    /**
     * 获取根结点
     * @param xml
     * @return
     * @throws DocumentException
     */
    public static Element getRootElement(String xml) throws DocumentException {
        Document document = Dom4jUtils.getDocumentByXml(xml);
        return document.getRootElement();
    }

    /**
     * 获取指定节点的子节点
     * @param node          父节点
     * @param childnode     指定名称的子节点
     * @return              返回指定的子节点
     */
    public static Element getChildElement(Element node,String childnode){
        if(null==node||null == childnode||"".equals(childnode.trim())){
            return null;
        }
        return node.element(childnode.trim());
    }

    /**
     * 获取所有的属性值
     * @param node
     * @param arg
     * @return
     */
    public static Map<String, String> getAttributes(Element node, String...arg){
        if(node==null||arg.length==0){
            return null;
        }
        Map<String, String> attrMap = new HashMap<>();
        for(String attr:arg){
            String attrValue = node.elementTextTrim(attr);
            attrMap.put(attr, attrValue);
        }
        return attrMap;
    }

    /**
     * 获取element的单个属性
     * @param node      需要获取属性的节点对象
     * @param attr      需要获取的属性值
     * @return          返回属性的值
     */
    public static String getAttribute(Element node,String attr){
        if(null == node||attr==null||"".equals(attr)){
            return "";
        }
        return node.elementTextTrim(attr);
    }

    /**
     * 添加孩子节点元素
     * @param parent 父节点
     * @param childName 孩子节点名称
     * @param childValue  孩子节点值
     * @return 新增节点
     */
    public static Element addChild(Element parent, String childName, String childValue) {
        Element child = parent.addElement(childName);// 添加节点元素
        child.setText(childValue == null ? "" : childValue); // 为元素设值
        return child;
    }

    /**
     * 添加二重节点赋值
     * @param parent
     * @param childName
     * @param map
     * @return
     */
    public static Boolean addChilds(Element parent, String childName,Map<String,Object> map) {
        Element child = parent.addElement(childName);// 添加节点元素
        try {
            Element childs = null;
            for(String key : map.keySet()){
                childs = child.addElement(key);// 添加节点元素
                childs.setText(map.get(key) == null ? "" : map.get(key).toString()); // 为元素设值
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    /**
     * 添加孩子节点元素
     * @param parent 父节点
     * @param args Map<String,Object>
     * @return boolean
     */
    public static boolean addChild(Element parent,Map<String,Object> args) {
        try {
            Element child = null;
            for(String key : args.keySet()){
                child = parent.addElement(key);// 添加节点元素
                child.setText(args.get(key) == null ? "" : args.get(key).toString()); // 为元素设值
            }
        }catch (Exception e){
            return false;
        }
        return true;
    }

    /**
     * DOM4j的Document对象转为XML报文串
     * @param document
     * @param charset
     * @return 经过解析后的xml字符串
     */
    public static String documentToString(Document document, String charset) {
        StringWriter stringWriter = new StringWriter();
        OutputFormat format = OutputFormat.createPrettyPrint();// 获得格式化输出流
        format.setEncoding(charset);// 设置字符集,默认为UTF-8
        XMLWriter xmlWriter = new XMLWriter(stringWriter, format);// 写文件流
        try {
            xmlWriter.write(document);
            xmlWriter.flush();
            xmlWriter.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return stringWriter.toString();
    }

    /**
     * 去掉声明头的(即<?xml...?>去掉)
     * @param document
     * @param charset
     * @return
     */
    public static String documentToStringNoDeclaredHeader(Document document, String charset) {
        String xml = documentToString(document, charset);
        return xml.replaceFirst("\\s*<[^<>]+>\\s*", "");
    }

    /**
     * 解析XML为Element对象
     * @param xml 被解析的XMl
     * @return Document
     */
    public final static Element parseXml(String xml) {
        StringReader sr = new StringReader(xml);
        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            document = saxReader.read(sr);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        Element rootElement = document != null ? document.getRootElement() : null;
        return rootElement;
    }

    /**
     * 获取element对象的text的值
     * @param e 节点的对象
     * @param tag 节点的tag
     * @return
     */
    public final static String getText(Element e, String tag) {
        Element _e = e.element(tag);
        if (_e != null)
            return _e.getText();
        else
            return null;
    }

    /**
     * 获取去除空格的字符串
     * @param e
     * @param tag
     * @return String
     */
    public final static String getTextTrim(Element e, String tag) {
        Element _e = e.element(tag);
        if (_e != null)
            return _e.getTextTrim();
        else
            return null;
    }

    /**
     * 获取节点值.节点必须不能为空，否则抛错
     * @param parent    父节点
     * @param tag       想要获取的子节点
     * @return          返回子节点
     */
    public final static String getTextTrimNotNull(Element parent, String tag) {
        Element e = parent.element(tag);
        if (e == null)
            throw new NullPointerException("节点为空");
        else
            return e.getTextTrim();
    }

    /**
     * 节点必须不能为空，否则抛错
     * @param parent    父节点
     * @param tag       想要获取的子节点
     * @return          子节点
     */
    public final static Element elementNotNull(Element parent, String tag) {
        Element e = parent.element(tag);
        if (e == null)
            throw new NullPointerException("节点为空");
        else
            return e;
    }

    /**
     * 将文档对象写入对应的文件中
     * @param document      文档对象
     * @param path          写入文档的路径
     * @throws IOException
     */
    public final static void writeXMLToFile(Document document,String path) throws IOException{
        if(document==null||path==null){
            return;
        }
        XMLWriter writer = new XMLWriter(new FileWriter(path));
        writer.write(document);
        writer.close();
    }

    /**
     * xml转Map
     * @param xmlStr
     * @return
     */
    public static Map<String, Object> xmlString2Map(String xmlStr) {
        Map<String, Object> map = new HashMap<String, Object>();
        Document doc;
        try {
            doc = DocumentHelper.parseText(xmlStr);
            Element el = doc.getRootElement();
            map = recGetXmlElementValue(el, map);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }
    /**
     * 循环解析xml
     * @param ele
     * @param map
     * @return
     */
    @SuppressWarnings({ "unchecked" })
    public static Map<String, Object> recGetXmlElementValue(Element ele, Map<String, Object> map){
        List<Element> eleList = ele.elements();
        if (eleList.size() == 0) {
            map.put(ele.getName(), ele.getTextTrim());
            return map;
        } else {
            for (Iterator<Element> iter = eleList.iterator(); iter.hasNext();) {
                Element innerEle = iter.next();
                recGetXmlElementValue(innerEle, map);
            }
            return map;
        }
    }

    public static Map<String, Object> iterateElement(Element element) {
        List<Element> node = getChildElements(element);
        Map<String, Object> obj = new HashMap<>();
        List list = null;
        for (Element child : node) {
            list = new LinkedList();
            String text = child.getTextTrim();
            if (StringUtils.isEmpty(text)) {
                if (getChildElements(child).size() == 0) {
                    continue;
                }
                if (obj.containsKey(child.getName())) {
                    list = (List) obj.get(child.getName());
                }
                list.add(iterateElement(child)); //遍历child的子节点
                obj.put(child.getName(), list);
            } else {
                if (obj.containsKey(child.getName())) {
                    Object value = obj.get(child.getName());
                    try {
                        list = (List) value;
                    } catch (ClassCastException e) {
                        list.add(value);
                    }
                }
                if (getChildElements(child).size() == 0) { //child无子节点时直接设置text
                    obj.put(child.getName(), text);
                } else {
                    list.add(text);
                    obj.put(child.getName(), list);
                }
            }
        }
        return obj;
    }
}
